Git教程和常用命令
个人使用git
的一些总结,一下常用命令的互相搭配使用,能非常完美的处理好日常遇到的99%
的情况(不敢说100%,得留点余地)。
还有一些使用频率非常低的指令没有记录,至少普通开发者非常不常用,以后可能会补充。
话不多说
首先需要先下载git
这个还是要说一下的
[TOC]
下面这一块内容请读者忽略,这里是我放的几条我个人常用的指令,免得往下找了,方便个人复制使用。 git config -l
只查看当前项目的git的配置 git config --global -l
查看全局git的配置 git remote prune origin
其他人删除线上某分支,自己这儿却还能看到,可以执行这个指令更新一下远程分支 git config branch.test.description '分支的注释'
用来给某个分支添加注释(注释信息只保存在本地,不能推送到远程仓库) git commit --amend -m "<新注释>"
把当前的修改,补充提交到之前最后一次提交中(相当于回滚一次,添加当前修改后,重新用新注释提交) git rev-list --count <分支名>
查看某个分支上面的提交数量,会打印一个数字
常用命令
最常用/版本对比/其他
git status
查看当前分支状态 git reflog
查看每一次的命令,都做过什么 git log
查看此分支完整的提交记录,回车继续看,q
停止 git log --oneline
查看此分支简略的提交记录,只展示提交号和提交注释 git show
查看最近一次提交的具体代码变化 git show <提交ID>
查看某次提交的具体代码变化 git diff
查看当前代码add
后,会add
哪些内容 git diff --staged
查看现在commit
提交后,会提交哪些内容 git diff HEAD
查看当前代码add
并提交后,会提交哪些内容 git log --oneline --graph
图形化展示当前分支相关的所有历史提交 git log --oneline --graph --all
图形化展示所有分支的历史提交和分支关系 git log --oneline --graph --all --simplify-by-decoration
图形化展示所有的分支的相互合并关系
初始化基本操作
git init
初始化仓库,默认为master
分支(最新版的git可能修改为了main
分支) git add -A
提交全部文件修改到缓存区 git add <具体某个文件路径+全名>
提交某些文件到缓存区 git commit -m "<注释>"
提交代码到本地仓库,并写提交注释 git commit --amend -m "<新注释>"
把当前的修改,补充提交到之前最后一次提交中(相当于回滚一次,添加当前修改后,重新用新注释提交)
git配置
git config -l
只查看当前项目的git的配置 git config --global -l
查看全局git的配置 git config <--global?> user.name
查看当前项目或全局的用户名 git config <--global?> user.email
查看当前项目或全局的用户邮箱 git config <--global?> user.name <用户名>
设置当前项目或全局的用户名 git config <--global?> user.email <邮箱>
设置当前项目或全局的用户邮箱
分支操作
git branch
查看本地所有分支 git branch -r
查看远程所有分支 git branch -a
查看本地和远程所有分支 git branch -v
查看分支和当前最新提交信息 git branch -vv
主要查看本地和远程分支的对应关系(就是使用 -u 绑定的分支) git merge <分支名>
合并分支 git merge --abort
合并分支出现冲突时,取消合并,一切回到合并前的状态 git branch <新分支名>
基于当前分支,新建一个分支 git checkout --orphan <新分支名>
新建一个空分支(会保留之前分支的所有文件) git branch -D <分支名>
删除本地某个分支 git push <远程库名> :<分支名>
删除远程某个分支 git branch <新分支名称> <提交ID>
从提交历史恢复某个删掉的某个分支 git branch -m <原分支名> <新分支名>
分支更名 git checkout <分支名>
切换到本地某个分支 git checkout <远程库名>/<分支名>
切换到线上某个分支 git checkout -b <新分支名>
把基于当前分支新建分支,并切换为这个分支 git remote prune <远程库名>
其他人删除线上某分支,自己这儿却还能看到,可以执行这个指令更新一下远程分支 git config branch.[分支名].description '分支的注释'
用来给某个分支添加注释(注释信息只保存在本地,不能推送到远程仓库) git config branch.[分支名].description
查看某个分支的注释
对于分支注释查看,可以安装分支注释查看工具npm install -g git-br
,然后使用git br
来查看本地所有分支的注释
推拉操作(push和pull)
git pull <远程仓库名> <远程分支名>
拉取远程仓库的分支与本地当前分支合并 git pull <远程仓库名> <远程分支名>:<本地分支名>
拉取远程仓库的分支与本地某个分支合并 git push <远程仓库名> <本地分支名>
推送本地某个分支到远程与其对应的分支上,远程没有则会给远程库新建分支 git push <远程仓库名> <本地分支名>:<远程分支名>
推送本地分支到远程某个分支 git push <远程仓库名> :<远程分支名>
删除远程某个分支 git push -f <同上的命令>
强制提交,覆盖线上 git fetch
获取线上最新版信息记录,不合并,用法和pull类似(一个特殊的操作,比如多人开发分支,其他人提交后,自己看分支的时候,可能还知不道线上的分支已经比自己的新了,需要这个指令,来获取一下线上的最新版本,会拉取,但不会合并,存在本地仓库中)
查看具体文件版本区别(git diff)
git diff <文件名>
对比最近提交,和近近次提交的区别,不加文件名,则为整体对比 git diff HEAD^ -- <文件名>
同上 git diff HEAD~<一个数字> -- <文件名>
上次提交和前第几次提交作对比 git diff <提交ID> <文件名>
上次提交和某次提交作对比 git diff <文件名>
工作区与暂存区比较 git diff HEAD <文件名>
工作区与最近提交比较 git diff <本地分支名> <文件名>
当前分支的文件与其他分支的文件进行比较
回滚操作 reset
真实硬性回滚,回到目标版本,比目标版本更新的提交记录,会全部丢失掉,操作和文件是否会丢失,取决于是否使用了--hard
。
--hard
:加上他,文件修改会被删除,丢失掉;不加他,文件修改会保留,都会处于add之前的状态。
这个指令可以用来把多次提交合并成一次。
比如小明切出一个新的功能分支,然后花了十次提交,开发完了一个很小的功能,但是感觉十次提交太浪费,会被同事看不起。
那么可以直接git reset <开始开发前的最后一次提交>
,然后git add -A
+git add -m "开发A功能"
+git push origin -f <分支名称>
,一套下来,神不知鬼不觉的,十次提交被压缩成了一次提交。。。当然如果这个功能分支已经被合并到主开发分支,或者被别人拉取过了,最好就别整了,那就变成欲盖弥彰了。。。
git reset <--hard?> HEAD^
回退到上次提交 git reset <--hard?> <提交记录>
回退到之前的某次提交 git reset <--hard?> <某个分支>
回退到此分支的提交状态,相当于复制分支过来 git reset <文件完整路径+完整名>
把add
过的某个文件撤销到未add
的状态 git reset
把add
过的所有文件撤销到未add
的状态 git checkout <文件完整路径+完整名>
一个还没有add
的文件,撤销修改 git checkout .
还没有add
的所有文件,撤销修改 git checkout -f
撤销当前所有未提交的修改 git commit --amend
修改commit
提交后,可使用此指令进入vim编辑器修改commit信息
重做 revert
比如小明正在和很多同事,一起开发一个项目。
这天,小明受命开发A功能,对很多文件进行了修改,开发完成后,就进行了提交'A功能开发',并且推送到远程仓库,其他同事们也进行了拉取。
可是,同事刚刚拉取完,领导突然说,A功能不要了,撤回去吧。
这时候,小明可以使用reset
进行回滚,然后硬性覆盖git push -f
提交,再通知其他所有拉取过'A功能开发'的同事,把本地代码回滚一下。
但这样操作实在低端,尤其当同事拉取了你的代码后,已经再开发、甚至已经有了自己的提交时,在进行回滚就比较烦人了,而且如果都过去一周了,领导再要求撤回去,那就更恶心人了。
所以这里可以使用revert
。
git revert <提交记录>
当执行这个指令时,git会先判断<提交记录>这次提交,用户对项目做了哪些修改,然后把用户做的修改再改回去,合并到当前(没看懂这行的,请仔细多阅读几遍)。
下面用例子进行解释
当我执行
git revert <提交记录one>
,等效于:
我请一个名叫小强的工人,他执行git checkout -b temp
,把当前这个分支切出一个名为temp的新分支。
小强先执行git reset --hard <提交记录one>
回到那次提交记录,接着,就问我这次记录我都修改了什么,他就一点点的改回去,没错,就是「手工回滚」。
修改完成后,他就提交了,并且通知我合并temp这个分支。
于是我就合并了,就是我执行git revert <提交记录one>
后看到的情况。
可能没有冲突,我高高兴兴合并了;也可能有严重冲突,比如小强「手工回滚」改回的代码里面,有我后面用到的,这时候我就要处理冲突了。
当我处理完成,进行add,然后commit提交,这次revert就完成了。此时,我的分支里面只多了一次提交(如果真按我上面的流程走,应该是两条,一条是小强在temp分支的那个提交,一个是我合并temp分支的提交,但这里使用
revert
,只有一次提交)。新的提交,对以前的提交不会产生一点影响,这个时候,小明就可以看做是完成了一个新的功能---'去掉A功能',然后正常push就行啦,大家皆大欢喜。
git revert HEAD
撤回当前最近的这次提交的修改 git revert <提交记录>
撤回<提交记录>那次的提交的修改
远程库和分支的链接操作
git remote -v
查看对应的远程仓库地址 git clone <远程仓库地址链接>
克隆某个远程库,默认库名为origin
git clone <远程仓库地址链接> <库名>
克隆某个远程库,并自定库名 git remote remove <远程仓库名>
和远程的某个仓库解除绑定关系 git remote add <远程仓库名> <远程仓库地址链接>
和某个远程仓库建立绑定关系 git remote set-url <远程仓库名> <要改为的远程仓库地址链接>
修改绑定的远程库链接 git push --set-upstream <远程仓库名> <远程分支名>
当前分支和远程某个分支建立绑定关系
储藏操作(stash)
经常有这样的事情发生,当你正在进行项目中某一部分的工作,里面的东西处于一个比较杂乱的状态。
而你想转到其他分支上进行一些工作。
问题是,你不想提交进行了一半的工作,否则以后你无法回到这个工作点。
解决这个问题的办法就是git stash命令。
git stash save <注释信息>
当前分支提交到储藏,插到储藏序列的最前面(不包括新建文件) git stash save -u <注释信息>
同上,会包括新建文件,功能更强大 git stash list
查看所有储藏中的工作 git stash drop <储藏的名称>
删除对应的某个储藏 git stash pop
取出储藏中最后存入的工作状态进行恢复,会删除储藏 git stash pop <储藏对应的数字>
取出储藏中对应的工作状态进行恢复,会删除储藏 git stash apply
取出储藏中最后存入的工作状态进行恢复,注意,不会删除储藏 git stash apply <储藏的名称>
取出储藏中对应的工作状态进行恢复,注意,不会删除储藏 git stash branch <新分支名> <储藏的名称>
从储藏中新建分支,会删除储藏 git stash clear
清空所有储藏中的工作
标签操作(tag)
tag
是什么,虽然整个开发过程,每个提交都对应一个提交ID,回滚也比较方便,但总有一些重大意义的提交,比如从v0.91升级到了v1.0,这个v1.0是必须要单独摘出来保存的,否则万一出现回滚事故,导致提交记录丢失呢?虽然可以单独新建分支保存,但分支的功能并不是用来做这个的。冗余的分支在开发时也容易产生误操作。
所以
tag
的用处就来了,他可以把某次提交后的项目,整个单独复制拎出来,命名为一个tag(可以以项目版本或打tag的时间来命名),可以写注释,存在tag列表中,与分支隔离开,除非专门命令操作,否则只要项目存在,他们就不会受到影响。同时,可以使用tag快速回滚项目、基于tag新建分支等,在项目整体的管理上非常方便。
git tag
列出本仓库中所有tag列表 git tag <tag名>'
基于最近的一次提交打tag(轻量tag,不推荐) git tag -a <tag名> -m '<此tag的注释>'
基于最近的一次提交打tag git tag -a <tag名> <提交ID> -m '<此tag的注释>'
基于某次提交打tag git show <tag名>
查看此tag的tag信息 git tag -d <tag名>
删除本地某个tag git push origin :refs/tags/<tag名>
删除远程仓库中的tag git push <远程仓库名> <tag名>'
推送某个tag至某个远程库 git push <远程仓库名> --tags'
推送所有tag至某个远程库 git checkout -b <新分支名> <tag名>'
基于某个tag新建分支
git查看分支提交历史:log
指令
查看分支提交历史,也可以通过参数,查看更复杂的提交、分支相互合并、分支存亡历史等。
git log
直接指示当前分支上的相关提交历史,关键就是他的参数,下面这些参数都可以组合使用:
--oneline # 【常用】省略大部分提交信息,只展示提交版本号 + 提交信息,很常用
--graph # 【关键】图形化展示这个分支相关的所有提交的来源
--simplify-by-decoration # 只展示合并信息,其他提交信息都忽略不显示
--decorate # 据说是用来可以显示出指向提交的指针的名字,也就是HEAD指针,但我实测貌似没有任何效果
如果只是想查看当前分支的提交记录,推荐使用下面的指令,它会删去一些平时不用关注的提交时间、提交者等信息。
git log --oneline
如果查看更复杂的分支信息,就需要用到关键参数「--graph
」了。
这个功能是我公司突然切换主战项目时,回到久不开发的项目,看到一大堆分支时,懵逼的我无奈开始研究的,建议没有特殊需要的,也不必往下看了,毕竟算是很不常用了。
先说一下,git自带一个图形界面,可以直接在git仓库文件夹下,执行gitk
,就可以调出一个图形界面,展示的形式和下面类似,只是会有更多附加信息,可以参考。
它主要有以下相关指令:
git log --oneline --graph
图形化展示当前分支相关的所有历史提交 git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
图形化展示当前分支相关的所有历史提交(带提交者和提交距今时间) git log --color --graph --pretty=format:'%C(bold white)%h%Creset -%C(bold green)%d%Creset %s %C(bold green)(%cr)%Creset %C(bold blue)<%an>%Creset' --abbrev-commit --date=relative
图形化展示当前分支相关的所有历史提交(带提交者和提交距今时间) git log --oneline --graph --all
图形化展示所有分支的历史提交和分支关系 git log --oneline --graph --all --simplify-by-decoration
图形化展示所有的分支的相互合并关系
它图形化展示这个分支相关的所有提交的来源,当使用以下指令时,会展示一个彩色的线和字组合的图形。
图形会很难理解,虽然乍一看都能看懂,看上去只是用线把一次次的提交,指向这里,又指向那里,一根线分叉为两个,两根线合并为一根。
这里大致说明几点:
- 图需要从下往上看,注意观看顺序。
- 这个图只是「提交」的去向图,和分支无关,分支只是用来承载「提交」的载体。
- 图的左侧,是用线和星号「*」展示的提交的分叉和合并,可以理解为铁路和站台。
- 一个星号代表一次提交,它右侧的字是这次提交的说明,且同一水平线上,只会同时有一个星号。
下面是例子+说明。
rebase 变基功能
rebase 变基功能,可以使项目中的提交历史干净整洁。
比如:
- 同一分支时:两个人同时拉取了某个分支的最新提交,各自开始开发并提交,最后合并代码时,这个分支时将出现无意义的分叉。
- 合并分支时:基于 dev 分支,checkout 了一个 dev2 分支,接着两个分支各自有了新的提交,最后把 dev2 合并到 dev 时,将出现无意义的分叉。
同一分支时
有开发者小明和大黄,小明初始化了项目,把项目推送到线上;然后大黄拉取项目,提交两次后 push 项目。
在大黄开发时,小明也提交了一个功能,push 前拉取项目,发现大黄有提交,则小明先 pull 拉取一下。
此时可能无冲突或者有冲突,如果没有冲突,则出现以下提示:
此时直接正常操作,编辑合并记录,或者直接使用默认合并提交即可(依次按下 :
wq
回车
)。
如果有冲突,则会出现以下提示,需要处理后再 add,最后提交:
无论是否有冲突,处理完成后,此时再查看提交记录:
会发现提交记录分叉了。。。但实际我们不想要这个分叉,复杂了提交记录,不便于阅读。
此时我们可以直接输入 git rebase
回车。
如果之前拉取时没有冲突,则随后控制台提示:
Successfully rebased and updated refs/heads/master.
说明变基成功,再查看提交记录:
相当于 git 帮我们把提交记录进行重新排列:回到 小明初始化
这个提交状态,拉取大黄的两条记录,补上小明的提交。
如果之前拉取时有冲突,则这里会麻烦一些,但原理和上面其实一样:回到 小明初始化
这个提交状态,拉取大黄的两条记录,补上小明的提交。。。不同的是这里「补上小明的提交」这一步,因为是有冲突的,所以这时又会出现冲突,需要再人工处理一遍。。。
确认冲突处理好之后,执行 git add -a
,然后再按照提示输入 git rebase --continue
,再写一下新的提交记录,即可。
如果处理冲突时,不想 rebase 了,则随时在控制台输入 git rebase --abort
,则可以退出 rebase,返回 rebase 之前的状态。
完成 rebase 后,虽然改变了提交和提交版本,但此时我们还没有提交,完全不影响线上,还把提交记录归一了,清晰明了了许多。
合并分支时
这个故事只有小明,小明这天接了个任务,于是基于 master 分支 checkout 了一个 dev 分支,在 dev 开始开发。
这时 master 分支出了一些 bug(或者合并了其他的分支),有了一些新的提交。
终于,dev 分支的功能开发完成,但如果此时直接把 dev 分支合并到 master,那后果可像而知,必然又将劈叉了,其结果如下所示:
这当然不行了,我们不想要劈叉的提交历史。
所以,回到 master 合并 dev 之前,使 master 回到 af08311
这个状态。
然后切换到 dev 分支,先看一下当前 dev 的提交记录:
可以知道,init 这个提交是发生在 master 分支的,后面两个提交,是 checkout 到 dev 分支后提交的。
然后开始执行变基:
git rebase master
执行后,如果 dev 的新内容,和 master 当前内容无冲突,则会直接打印:
Successfully rebased and updated refs/heads/dev.
此时再查看 dev 的提交记录:
发现,在 dev 分支的提交记录变了,master 新的那两个提交,也出现在 dev 分支前面,虽然提交的版本号还是变了(肯定还和 dev 分支的远程仓库分支的提交不同了),但关键是,此时再把 dev 合并到 master 分支,是不会再劈叉的了,而且,dev 分支作为功能分支,本身是不太重要的,完全可以把 dev 分支,覆盖推送一下。
出现冲突
上面是执行 git rebase master
后无冲突时的情况,顺风顺水,而当有冲突的时候,就麻烦了。
比如我们在 dev 分支添加两条我们确定会有冲突的修改并提交,再进行 rebase。
这里其实也就暴露了 rebase 的比较细的过程:rebase 过程中,会把 dev 分支的新提交们,一个个拿出来和 master 对比,如果无冲突,直接无感合并。
但如果发现某个提交有冲突,rebase 过程会卡住,然后会让你处理冲突,这个提交的冲突处理完成,手动执行一下 git add -A
(控制台会有提示,也会提示终止 rebase 的指令),然后按照提示再执行 git rebase --continue
,则此条提交处理完成,再拿出 dev 分支的下面一条提交,继续判断,直到所有提交处理完成。
最终处理完成后,dev 分支的每条提交都会保留,当然都是处理完冲突的:
也就完成了 rebase 的使命。
.gitignore文件
在使用Git的过程中,有的文件比如日志、临时文件、编译的中间文件等不要提交到代码仓库,这时就要设置相应的忽略规则,来忽略这些文件的提交。
没错就是.gitignore
文件了。
此文件需要放在.git
(默认是隐藏文件,是git的本地仓库)同一目录下
写法如下:
.DS_Store
.parcel-cache
.cache
node_modules
dist
dist-ssr
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Editor directories and files
.idea
.vscode
*.suo
*.ntvs*
*.njsproj
*.sln
*.local
这样,当git add
的时候,上面定义忽略的那些文件,就会被git忽略,发生了变化git也不会管。
然而有时候,是会出现意外的。
比如,git已经提交过了,这是后突然说,这里面有个文件需要被忽略,然后我把这个文件写到了.gitignore
文件中。。。无效!这个文件仍然没有被忽略!
这是就需要如下命令,来删除此文件并忽略
# 在git库中删除文件并停止追踪,但实际文件还保留,只是忽略掉。
git rm -r --cached <文件路径+文件全名>
由此,方可。
git 给指令设置别名
类似于Linux系统的alias别名功能,git也可以使用它,给git指令设置别名。
这里只举一个例子,比如下面的指令,虽然很好用,但是实在太长了,想要使用只能靠复制:
# 图形化展示当前分支相关的所有历史提交(带提交者和提交距今时间)
git log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit
所以这里,可以使用git的alias功能,给他设置为git的全局一个'别名',相当于给git再人工拓展一条指令,直接输入以下:
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
然后再输入:
git lg
此时,git lg
的效果,和那老长一条的指令的效果一模一样。
其他如果有想缩减的git指令,可以同理设置。
使用多套账户和密码时的区分
以下方法仅适用于只使用账户和密码时的情况,其实更推荐使用 SSH 方案,更方便且安全。
注意下面这个方法,需要确保github登录密码只是字母、数字、下划线、横杠等等,如果有其他特殊字符,不确保能否成功,因为需要把密码写在url中,可能密码中的一些特殊字符,url不支持,也就出问题了。
有时会有这样的需求,一个项目,需要推送到github的两个账户的两个仓库下面。
比如自己项目默认的远程分支是:
仓库1
仓库名称1:origin_1
仓库地址1:https://github.com/account_1/item.git
账户名1:account_1
密码1:passwork_1
这是上面通知,需要同时把项目往下面一个账户上推送
仓库2
仓库名称2:origin_2
仓库地址2:https://github.com/account_2/item_share.git
账户名2:account_2
密码2:passwork_2
方法一(笨方法,明白原理的可以直接看方法二):
先添加仓库:
git remote add origin_2 https://github.com/account_2/item_share.git
再进行提交:
git push origin_2 master
那这里会报错无权限,因为此时电脑中记住的github账户名密码是仓库1
的那一套。
这时可以通过修改系统记住的github账户,改成仓库2
的,但这样比较麻烦,每次推送都需要来回修改。
【解决办法】:
修改当前本地项目的git配置,文件为当前项目地址下的.git/config
,可以先查看一下当前配置:cat .git/config
:
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
precomposeunicode = true
[remote "origin_1"]
url = https://github.com/account_1/item.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "master"]
remote = origin
merge = refs/heads/master
这里修改此文件,添加下面这一段
[remote "origin_2"]
url = https://账户名2:密码2@github.com/account_2/item_share.git
fetch = +refs/heads/*:refs/remotes/origin/*
保存后,再进行推送git push origin_2 master
就可以了,自此推送origin
时,自动使用全局保存的账户和密码,推送origin_2
时,自动使用这里配置的账户名和密码。
方法二:
可以在添加仓库的时候,直接在仓库地址中加上账户名和密码:
git remote add origin_2 https://账户名2:密码2@github.com/account_2/item_share.git
上一步可能报错类似
-bash: ... event not found
,这是因为 clone 的这个地址,实际是一个 url,但给 url 添加的账户名或密码,格式中可能包含 url 无法解析的字符。如果有这种情况,那就老实用方法一吧。
然后再进行提交:
git push origin_2 master
可以直接成功,完成。
使用 SSH
绑定一个远程仓库,有两种方式:
- 使用http链接的方式
- 使用ssh加密链接的方式
如果远程仓库为公开仓库,则两者在使用上,区别不大;
但如果是私密仓库,http 方式是需要连接远程仓库时输入用户名和密码,这就导致账号和密码容易暴露,因为任何人在任何设备上,都可以使用这套账号和密码连接仓库,不够安全,且当同一台电脑,需要开发不同远程仓库的项目时,可能还会搞混账户和密码。
所以就有了下面更合适的方式 ssh。
ssh 只需要本地设备使用指令生成一对公钥和私钥,然后把公钥的内容,复制添加到远程库的设置中,让远程库认识此设备,再复制项目的 ssh 链接,来绑定这个远程仓库,这种方法,远程仓库会只认设备不认账户,只要保证设备是安全的,仓库就是安全的,就算设备丢失,也不需要更换密码,只用登录远程仓库页面,删除这个设备的公钥即可。
此外,一个设备能生成多对公钥和私钥,通过 ssh 的 config 文件来管理,能够轻松解决不同远程仓库的问题。
基础使用 SSH
# 默认生成一对名为 id_rsa 的公钥和私钥:公钥名:id_rsa.pub 私钥名:id_rsa
ssh-keygen
# 生成指定名称的 公钥私钥
ssh-keygen -f id_new # 生成一对名为 id_new 的公钥和私钥
不同系统存放的默认存放位置:
- windows:C盘/用户/<用户名称>/.ssh
- MacOs:~/.ssh
- Linux:/root/.ssh
.ssh 文件夹中,有两种格式的文件:
- .pub 格式为公钥,需要打开复制其中的内容,粘贴到需要的git远程仓库网站的账户设置中。
- 同名的无后缀名的为这个公钥对应的私钥,不要动他,也不要发给其他任何人,放在这个位置保管好。
注:一个ssh钥匙对,在一个git远程仓库网站中,只能被一个用户添加。
如果有另一个用户,也想把仓库共享给这台设备,再次写入公钥,则会失败。
注意,当添加完ssh,本地拉取github代码时,可能会出现下面的提示
# 输入
git clone git@github.com:***/***.git
# 输出
Cloning into '***'...
The authenticity of host 'github.com (13.229.188.59)' can't be established.
RSA key fingerprint is SHA256:***.
Are you sure you want to continue connecting (yes/no)?
注意这里,一定要输入 yes 再回车,否则会报错。
上面虽然只生成了一套秘钥,但可以把公钥同时配置到不同网站中,比如 github、gitee、gitlab 等等,当多个不同网站的 git 项目进行推拉时,虽然都会使用同一份秘钥,但其实也都可以正常生效。
同一远程仓库下的多个账户
场景:同一个远程仓库,比如都是 github 的项目,但是有多个账户,A 项目在 A 账户,B 项目在 B 账户中。
比较大力无脑的方法,就是照样还是同一个公钥,分别配置到账户 A 和 账户 B 的配置中,依然可以使用。
但有时候我们就是需要区分一下,给两个账户使用两套 ssh。
回到生成 ssh 之前,先分别生成多个 SSH 钥匙对:
# A 项目的钥匙对
ssh-keygen -f id_A
# B 项目的钥匙对
ssh-keygen -f id_B
生成完毕后,进入对应存放ssh钥匙对的.ssh文件夹中,会发现多两对秘钥:
# SSH 的文件夹中
# A 项目的秘钥对文件
id_A
id_A.pub
# B 项目的秘钥对文件
id_B
id_B.pub
下面开始配置,分别登陆两个账户,找到设置 SSH 的页面,把 A 账户的公钥内容设置到 A 账户中,B 账户的公钥内容设置到 B 账户中。
然后,可以拿到 github 中的用户 A 和用户 B 对应的两个项目的项目的 ssh 链接:
git@github.com:account-a/item-a.git
git@github.com:account-b/item-b.git
但这里我们不能再直接使用了,因为两个的域名完全一样,ssh 无法区分两者了,所以需要把连接修改一下备用:
git@a.github.com:account-a/item-a.git
git@b.github.com:account-b/item-b.git
接着,打开开发电脑的 ~/.ssh/config 文件(如果没有这个文件,就创建这个文件)配置一下,让我们在拉取项目时,ssh 能使用对应的正确的秘钥,内容如下:
Host a.github.com # 域名拦截
HostName github.com # 拦截成功后,重新指向的域名,这里需要写正确的
User git
IdentityFile ~/.ssh/id_A
PreferredAuthentications publickey
Host b.github.com # 域名拦截
HostName github.com # 拦截成功后,重新指向的域名,这里需要写正确的
User git
IdentityFile ~/.ssh/id_B
PreferredAuthentications publickey
此时,设备可以成功绑定这两个账户的仓库,可以输入一下指令,来验证ssh校验是否通过:
ssh -T a.github.com
# 出现以下打印,说明成功
# Hi user-B! You've successfully authenticated, but GitHub does not provide shell access.
之后,就可以各自去执行克隆指令,拉取项目,各自开发,各自推送,互不影响又各自正常运行,这里记得要用修改过的链接:
# 克隆 A 账户的 A 项目
git clone git@a.github.com:account-a/item-a.git
# 克隆 B 账户的 B 项目
git clone git@b.github.com:account-b/item-b.git
依次类推,设备绑定多个账户,不再是问题,关键就是配置config
文件,能够对应起来即可。
拓展提示
可以发现,我们修改后的域名和 .ssh/config 中配置的 Host 域名是对应的:
# 修改后的域名为 a.github.com
git@a.github.com:account-a/item-a.git
# .ssh/config 中的 Host 也为 a.github.com
Host a.github.com # 域名拦截,仓库域名
HostName github.com # 拦截成功后,重新指向的域名,这里需要写正确的,可以设置为 ip
...
其实,我们这里的域名可以随意设置,只要两者能对应,再把 HostName 配置正确就OK,比如如下的配置也是可行的:
# 修改后的域名为 my-item
git@my-item:account-a/item-a.git
# .ssh/config 中的 Host 也为 my-item
Host my-item
HostName 132.132.132.132 # 这里也可以设置为 ip
...
Git安装完成后的设置
用户名、邮箱、登录账户
git config -l
只查看当前项目的git的配置 git config --global -l
查看全局git的配置 git config <--global?> user.name
查看当前项目或全局的用户名 git config <--global?> user.email
查看当前项目或全局的用户邮箱 git config <--global?> user.name <用户名>
设置当前项目或全局的用户名 git config <--global?> user.email <邮箱>
设置当前项目或全局的用户邮箱
修改用户登录信息
- window
控制面板 -> 用户账户 -> 管理 Windows 凭据
,即可看到普通凭据中有git的账户信息,可编辑更改 - Mac
钥匙串访问.app -> 右上角搜索git
,即可看到,可编辑更改
在比较新的git版本拉取代码时,会出现一下提示:
warning: Pulling without specifying how to reconcile divergent branches is
discouraged. You can squelch this message by running one of the following
commands sometime before your next pull:
git config pull.rebase false # merge (the default strategy)
git config pull.rebase true # rebase
git config pull.ff only # fast-forward only
You can replace "git config" with "git config --global" to set a default
preference for all repositories. You can also pass --rebase, --no-rebase,
or --ff-only on the command line to override the configured default per
invocation.
Already up to date.
这个提示在任何项目的每次下拉,都会出现,想要解决,就需要按照他的提示进行设置,可以直接在控制台输入一下指令,直接回车,就设置完成,以后不会再出现了:
git config --global pull.rebase false
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。